import ErrorCode from '../constants/ErrorCode';

export interface Params extends RequestInit {
  url: string,
  inputValue?: any,
  timeout?: number,
  upload?: boolean,
  type?: string,
  toastArgs?: Object
}

function handleTimeout(promise: Promise<any>, timeout: Number) {
  return Promise.race([promise, new Promise((ignored, reject) => {
    setTimeout(() => {
      reject('http request timeout');
    }, timeout);
  })]);
}

async function handleWebFileDownload(url, response) {
  let result = await response.blob();
  let disposition = response.headers.get('Content-Disposition');
  let reg = new RegExp('filename=".*"', 'i');
  let tmp = reg.exec(disposition);
  let filename = 'download';
  if (tmp && tmp[0] && tmp[0].trim() !== '') {
    filename = eval(tmp[0]);
  }
  let aLink = document.createElement('a');
  document.body.appendChild(aLink);
  let evt = document.createEvent('HTMLEvents');
  evt.initEvent('click', false, false);
  aLink.download = filename;
  aLink.href = window.URL.createObjectURL(result);
  aLink.click();
  window.URL.revokeObjectURL(url);
  aLink.dispatchEvent(evt);
}

/**
 * 网络请求封装
 * @author 田尘殇Sean(sean.snow@live.com)
 * @date 16/4/7
 */
export default class Request {

  private static isSuccessful(response): boolean {
    return response.status >= 200 && response.status < 300;
  }

  private static isDownload(response): boolean {
    return response.headers.get('Content-Type').includes('octet-stream');
  }

  static urlArgs(params: Object): String {
    if (!params) {
      return '';
    }

    return Object.keys(params)
      .map(key => `${key}=${params[key] || (params[key] === 0 ? params[key] : '')}`)
      .join('&');
  }

  static async execute({method = 'GET', type, url, timeout = 60000, upload, headers, inputValue, ...other}: Params) {
    const reqArgs: any = {
      ...other,
      method,
      headers: {
        ...headers,
        'Content-Type': 'application/json; charset=UTF-8'
      }
    };

    if (upload) {
      Reflect.deleteProperty(reqArgs.headers, 'Content-Type');
    }

    let payload: any = {};
    try {
      console.log(`request ${url}`, reqArgs);
      let response = await handleTimeout(fetch(url, reqArgs), timeout);
      if (Request.isSuccessful(response)) {
        if (Request.isDownload(response)) {
          await handleWebFileDownload(url, response);
        } else {
          payload = await response.json();
        }
      } else {
        payload = {
          success: false,
          status: ErrorCode.EXCEPTION
        };
      }
      payload.response = response;
      console.log(`${url} response status -> ${response.status}, response payload -> `, payload);
    } catch (e) {
      console.warn(url, reqArgs, e);
      payload = {
        success: false,
        status: ErrorCode.NETWORK_ERROR
      };
    }

    payload.inputValue = inputValue;

    return type ? {type, payload} : payload;
  }

}
